package com.ykc.helper;

import com.ykc.proxy.AspectProxy;
import com.ykc.proxy.Proxy;
import com.ykc.proxy.ProxyFactory;
import com.ykc.proxy.TransactionProxy;
import com.ykc.spring.Aspect;
import com.ykc.spring.Component;
import com.ykc.utils.ClassUtil;

import java.lang.reflect.InvocationTargetException;
import java.util.*;

//切面编程助手类
/**
 *
 * @Author Ykc
 * @Date 2021-05-16 22:37:18
 * @Description 得到一个beanClass->被Aop代理的类，的Map
 *
 **/
public class AopHelper {

    private static Map<Class<?>, Object> aopMap=new HashMap<Class<?>, Object>();
//    public AopHelper(){
    static {
        //将AOP类织入被代理类
        weavIn();
    }

    public static void weavIn(){
        try {
            //切面的实现类-被Aspect注解的目标类集合的映射
            Map<Class<?>,Set<Class<?>>> aspectMap=createAspectMap();
            //目标类-切面对象列表的映射
            Map<Class<?>, List<Proxy>> targetMap=createTargetMap(aspectMap);
            //把切面类织入目标类中，创建代理对象
            //TODO : 什么是切面类织入目标类，忘记了
            for (Map.Entry<Class<?>,List<Proxy>> targetEntry:targetMap.entrySet()){
                Class<?> targetClass = targetEntry.getKey();
                List<Proxy> proxyList=targetEntry.getValue();
//                Object instance=doCreateBean(targetClass,beanHelper.getSingletonObjects());
                Object proxy= new ProxyFactory().createProxy(targetClass,proxyList);
                //覆盖Bean容器里目标类对应的实例, 下次从Bean容器获取的就是代理对象了
                BeanHelper.setBean(targetClass,proxy);
            }
        }catch (Exception e){
            e.printStackTrace();
        }
    }

    /***************************************************************************************************/
    /***********************************获取切面类-目标类集合的映射****************************************/
    /***************************************************************************************************/
    public static Map<Class<?>, Set<Class<?>>> createAspectMap() throws Exception {
        Map<Class<?>, Set<Class<?>>> aspectMap = new HashMap<Class<?>, Set<Class<?>>>();
        addAspectProxy(aspectMap);
        addTransactionProxy(aspectMap);
        return aspectMap;
    }

    /**
     *  获取普通切面类-目标类集合的映射
     */
    public static void addAspectProxy(Map<Class<?>, Set<Class<?>>> aspectMap) throws Exception {
        //获取所有实现了AspectProxy抽象类的集合
        Set<Class<?>> aspectClassSet=ClassHelper.getClassSetBySuper(AspectProxy.class);

        //从这些类中拿出被Aspect注解的类
        for (Class<?> aspectClass:aspectClassSet){
            if (aspectClass.isAnnotationPresent(Aspect.class)){
                Aspect aspect=aspectClass.getAnnotation(Aspect.class);
                //与该切面对应的目标包的类的集合
                Set<Class<?>> targetClassSet=createTargetClassSet(aspect);
                aspectMap.put(aspectClass,targetClassSet);
            }
        }
    }

    public static void addTransactionProxy(Map<Class<?>, Set<Class<?>>> aspectMap) throws Exception {
        //获取所有实现了AspectProxy抽象类的集合
        Set<Class<?>> serviceClassSet = ClassHelper.getClassSetByAnnotation(Component.class);
        aspectMap.put(TransactionProxy.class, serviceClassSet);
    }

    public static Set<Class<?>> createTargetClassSet(Aspect aspect) throws Exception {
        Set<Class<?>> targetClassSet=new HashSet<Class<?>>();
        //包名
        String pkg=aspect.pkg();
        //类名
        String cls=aspect.cls();

        //如果包名与类名均不为空，则添加指定类
        if (!pkg.equals("")&&!cls.equals("")){
            targetClassSet.add(Class.forName(pkg+"."+cls));

        }else if (!pkg.equals("")){
            //获取包pkg下的所有类
            targetClassSet.addAll(ClassUtil.getClassSet(pkg));
        }
        return targetClassSet;
    }
    /***************************************************************************************************/
    /***************************************************************************************************/


    /***************************************************************************************************/
    /******************获取目标类-切面AOP对象列表的映射（因为一个目标类可能对应多个Aop类）********************/
    /***************************************************************************************************/
    public static Map<Class<?>, List<Proxy>> createTargetMap(Map<Class<?>,Set<Class<?>>> aspectMap) {
        Map<Class<?>, List<Proxy>> targetMap=new HashMap<Class<?>, List<Proxy>>();

        for (Map.Entry<Class<?>, Set<Class<?>>> proxyEntry:aspectMap.entrySet()){
            //切面类
            Class<?> aspectClass=proxyEntry.getKey();
            //目标类集合
            Set<Class<?>> targetClassSet=proxyEntry.getValue();
            //创建目标类-切面对象列表的映射关系
            for (Class<?> targetClass:targetClassSet){
                //切面对象
                try {
                    Proxy aspect=(Proxy) aspectClass.getDeclaredConstructor().newInstance();

                    if (targetMap.containsKey(targetClass)){
                        targetMap.get(targetClass).add(aspect);
                    }else{
                        List<Proxy> aspectList=new ArrayList<Proxy>();
                        aspectList.add(aspect);
                        targetMap.put(targetClass,aspectList);
                    }

                } catch (InstantiationException e) {
                    e.printStackTrace();
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                } catch (InvocationTargetException e) {
                    e.printStackTrace();
                } catch (NoSuchMethodException e) {
                    e.printStackTrace();
                }
            }
        }
        return targetMap;
    }

    public Map<Class<?>, Object> getProxyMap() {
        return aopMap;
    }

    public void setProxy(Map<String, Object> proxy) {



    }
}
